ECE 4160 Fast Robots

Raphael Fortuna


Lab reports made by Raphael Fortuna @ rafCodes Hosted on GitHub Pages — Theme by mattgraham

Home

Lab 2: Bluetooth

Summary

In this lab, I set up Bluetooth Low Energy (BLE) communication on the Artemis and the environment for Arduino and Python code in the prelab. I also completed five different communication tasks between my computer and the Artemis including sending and receiving data, creating new commands, and creating services for receiving and processing incoming Artemis data as described below.

Prelab

I followed the lab instructions and created a virtual environment for Python and installed the Jupyter notebook along with several Python packages. I also downloaded the codebase and went through the different functions for the ArtemisBLEController class. I installed the Arduino BLE as was able to flash the Artemis with ble_arduino.ino to get the MAC address as, shown below, and added it to the connection.yaml file in the Python codebase to connect with the board. I also changed my UUID and updated it in connection.yaml as well.

I was unable to connect the Jupyter notebook to the Artemis due to issues with BLE and Windows 11, so I took all the code from the notebook and placed it in a Python file and passed the full file path to the connection.yaml file to the ArtemisBLEController class config argument. I also did not change line 53 in base_ble.py to True as this caused Python to be unable to connect to the Artemis. These changes allowed me to connect to the Artemis as seen below :

MAC address and default code running for arduino

MAC address and default code running for Python

Codebase

The codebase on the Arduino side contains the advertising and service generation needed for the BLE connection as well as sending messages. Class BLECStringCharacterisitic is used to define different characteristics and send data, class EString makes it easy to package data together and send it via a characteristic, class RobotCommand helps process commands sent from the laptop, and the commands are run by handle_command() in ble_arduino.ide.

The codebase on the Python side uses bleak to connect to the Artemis and saves the Artemis MAC address and BLE UUIDs in connection.yaml. It can send and receive commands from the Artemis using the ArtemisBLEController class.

Command names are shared and stored in the Python and Arduino code as enums.

Bluetooth Connection

The Bluetooth connection is through BLE, ArduinoBLE on the Arduino side, and Bleak on the Python side. Devices are identified with MAC addresses and BLE passes information through services which have channels that send data back and forth between devices called characteristics. Devices can be peripherals that update characteristics from sensors (the Artemis here) by streaming data or a central device (the laptop with the python code) that read and write from/to a characteristic. A characteristic has a UUID used to write and read to it and identify it.

Send Echo Command Task

To add the echo command, I added code to the Artemis to extract the value sent from Python and then appended three different messages to the tx_estring_value to be sent via the tx_characterisitic_string. The python code sent the ECHO command with the argument “hello” and received a string.

Arduino showing value sent

Python showing value sent

Get Time Command Task

To add the time command, GET_TIME_MILLIS was added to the Artemis and Python enums containing the commands and a new case statement was added to the Artemis with a helper function that appended “T:” and the time in milliseconds to the tx_estring_value. The python code sent the GET_TIME_MILLIS command and received a string of the time, which it then printed.

Arduino showing value sent

Python showing value sent

Notification Handler Task

This involved creating a helper function in Python that took in a uuid and a bytearray as inputs and printed the converted bytearray. This was used as the callback function for the start_notify with uuid for RX_STRING. I then sent two commands of GET_TIME_MILLIS to make sure they were received and printed. No changes were needed on the Artemis side.

Arduino showing value sent

Python showing value sent

Get 5 Temperature Readings Command Task

To process multiple temperature readings, I added a “|” in between each time and value and split them by “|” in the start_notify helper function and activated it for this task. I also added a GET_TEMP_5s command to the Python and Artemis command enums. In the Artemis, I added another case statement for GET_TEMP_5s and a loop to append the time to tx_estring_value and add on the temperature using the another helper function that added the temperature to tx_estring_value using the Arduino getTempDegC() function. This was done five times over five seconds, with each reading sent individually.

Python showing value sent

Get 5 seconds of Temperature Readings Command Task

Here I had to get five seconds worth of temperature data, so I sent a pair of temperature readings with their respective time stamps from the Artemis to my laptop and was able to send ~180 points over those five seconds. I added the GET_TEMP_5s_RAPID command to the Artemis and Python enums and used the previous helper functions to assemble and send the temperature data from the Artemis.

I also added a function to leave the Python instance alive and idle for a given time so that all temperature data would be received as seen below. 182 values were sent and recieved, with only some shown in the Python photo.

Arduino showing value sent

Python showing value sent

Limitations Task

Assuming all RAM is available (and not considering overhead or other stored variables),

384 kB *1024 bytes/kB * 8 bits/bytes = 3145728 bits RAM, same value shown when the Artemis board is flashed.

150 Hz of 16 bit values for 5 seconds is 12000 bits, 2400 bits/second

So, this means that the RAM can hold 3145728/12000 = 262.144 groups of 5 seconds of data, which is 1310.72 seconds of data, or 21.84 minutes of data.

This is quite a lot, but this is assuming 1 16-bit value per 150 Hz and given there are multiple data streams and more overhead, every extra 16-bit value stored reduces the amount of data time.

2 16-bit values: 10.92 minutes

3 16-bit values: 7.28 minutes ….

21.84/x minutes, so at 10 16-bit values at 150 Hz, this is only 2.184 minutes of storage. So not that much space, so this data needs to either be sent quickly or compressed into a “summary” value.